package cgl.narada.service;

import java.util.Enumeration;
import java.util.Hashtable;

public class ServicePropertiesFactory {

	private static final ServicePropertiesFactory instance = new ServicePropertiesFactory();

	private Hashtable entityAndPropertiesTable;
	private Hashtable entityAndConfigTable;
	
	private Hashtable globalPropertyList;
	private GlobalServiceProperties globalServiceProperties;
	
	private String moduleName = "ServicePropertiesFactory: ";

	private ServicePropertiesFactory() {
		entityAndPropertiesTable = new Hashtable();
		entityAndConfigTable = new Hashtable();

		globalPropertyList = new Hashtable();
		globalServiceProperties = new GlobalServiceProperties();
		initializePendingGlobalServiceProperties();
	}

	public static ServicePropertiesFactory getInstance() {
		return instance;
	}
	
	/** 
	 * Here we keep track of all the global service properties that need to be
	 * initialized. The first time we encounter a property (and the assorted value)
	 * that property is recorded with the global service properties and removed 
	 * from the pending list.
	 */
	private void initializePendingGlobalServiceProperties() {
		globalPropertyList.put("NB_HOME", "NB_HOME");
	}

	/** Retrieve the global service properties. */
	public GlobalServiceProperties getGlobalServiceProperties() {
		return globalServiceProperties;
	}
	
	
	public synchronized void 
	intializeServiceProperties(int entityId) throws ServiceException {
		String errorReport = null;
		
		if (entityId == 0) {
			errorReport = moduleName + "The specified entityId=0 is NOT valid.";
			throw new ServiceException(errorReport);
		}

		Object entityKey = new Integer(entityId);
		if (entityAndConfigTable.containsKey(entityKey)) {
			String configLocation = (String) entityAndConfigTable.get(entityKey);
			errorReport = moduleName + "ServiceProperties for entity ["
					+ entityId + "] has been previously initialized with file ["
					+ configLocation + "]";
			throw new ServiceException(errorReport);
		}
		ServiceProperties serviceProperties = new ServiceProperties();
		entityAndPropertiesTable.put(entityKey, serviceProperties);
		checkGlobalPropertyList(serviceProperties);
		return;
	}
	
	
	public synchronized void 
	intializeServiceProperties(int entityId, String configFileLocation) 
	throws ServiceException {
		String errorReport = null;
		
		if (configFileLocation == null) {
			errorReport = moduleName+ "The specified file location for entityId [" + 
				entityId + "] is null";
			throw new ServiceException(errorReport);
		}

		if (entityId == 0) {
			errorReport = moduleName + "The specified entityId=0 is NOT valid.";
			throw new ServiceException(errorReport);
		}

		Object entityKey = new Integer(entityId);
		if (entityAndConfigTable.containsKey(entityKey)) {
			String configLocation = (String) entityAndConfigTable.get(entityKey);
			errorReport = moduleName + "ServiceProperties for entity ["
					+ entityId + "] has been previously initialized with file ["
					+ configLocation + "]";
			throw new ServiceException(errorReport);
		}

		ServiceProperties serviceProperties = new ServiceProperties();
		boolean loadingSuccessful = 
			serviceProperties.initialize(entityId, configFileLocation);

		if (loadingSuccessful) {
			entityAndPropertiesTable.put(entityKey, serviceProperties);
			entityAndConfigTable.put(entityKey, configFileLocation);
			checkGlobalPropertyList(serviceProperties);
			return;
		} else {
			errorReport = moduleName + "There were problems initializing"
					+ " with specified file [" + configFileLocation + "]."
					+ " Please check specified .properties file!";
			throw new ServiceException(errorReport);
		}
	}

	/**
	 * Checks to see if ServiceProperties associated with a certain entityId have
	 * been registered.
	 * 
	 * @param entityId
	 *           The identifier of the entity in question.
	 * @return true if ServiceProperties exist OR false otherwise.
	 */
	public boolean hasServiceProperties(int entityId) {
		Object entityKey = new Integer(entityId);
		if (entityAndPropertiesTable.containsKey(entityKey)) {
			return true;
		}
		return false;
	}

	/**
	 * Retrieves the ServiceProperties associated with the specified entityID
	 * 
	 * @param entityId
	 *           The identifier of the entity in question.
	 * @return The associated ServiceProperties. NULL otherwise.
	 */
	public ServiceProperties getServiceProperties(int entityId) {
		Object entityKey = new Integer(entityId);
		if (entityAndPropertiesTable.containsKey(entityKey)) {
			ServiceProperties serviceProperties = 
				(ServiceProperties) entityAndPropertiesTable.get(entityKey);
			return serviceProperties;
		}
		return null;
	}

	
	/** Check to see if any of the global service properties need to be
	 * initialized. If they have to be check to see if the supplied service 
	 * properties contains any of these properties. If it does proceed to 
	 * add to global property list and make sure that the property is removed
	 * from the pending list.
	 * @param serviceProperties The service properties to check against.
	 */
	private void checkGlobalPropertyList(ServiceProperties serviceProperties) {
		if (globalPropertyList.size() == 0) {
			return;
		}
		
		Enumeration e = globalPropertyList.keys();
		while (e.hasMoreElements()) {
			String globalProperty = (String) e.nextElement();
			if (serviceProperties.hasProperty(globalProperty)) {
				String globalValue = serviceProperties.getProperty(globalProperty);
				globalServiceProperties.addProperty(globalProperty, globalValue);
				globalPropertyList.remove(globalProperty);
			}
		}/* end while */
	}

}